#include "encodevideo.h"

EncodeVideo::~EncodeVideo()
{

}

EncodeVideo::EncodeVideo():QThread()
{

    this->register_all();

    //initEncode();

}

void EncodeVideo::register_all()
{
    av_register_all();
}

void EncodeVideo::initEncode()
{
    this->YuvQueue.clear();
    this->x=0;
    this->setIsStop(false);
    this->formatContex=avformat_alloc_context();
    this->pkt=av_packet_alloc();
    this->pktIndex=0;
    this->con=MyControl::getInstance();



    //1.通过文件的后缀得到最佳输出格式
    QDateTime currentDateTime = QDateTime::currentDateTime();
    QString timeStr = currentDateTime.toString("yyyy-MM-dd-hh-mm-ss");
    this->videooutName=timeStr;

    this->model=this->con->getModel("device_info");
    Any ret=this->model->sqlSelect("select *from device_info;");
    Device* device=ret.cast_<Device*>();


    QString fullFileName =device->getVideoPath()+"/"+timeStr+".H264";

    qDebug()<<"fullFileName="<<fullFileName;
    this->videooutPath=fullFileName;
    //"../fileout/Warcraft3_End.H264"
    AVOutputFormat*outputformat=av_guess_format(nullptr,fullFileName.toStdString().c_str(),nullptr);
    qDebug()<<fullFileName.toStdString().c_str();
    if(outputformat==nullptr)
    {
        qDebug()<<"av_geuss_format fail";
    }
    else {
        qDebug()<<"av_geuss_format success";
    }
    //1-1设置格式
    this->formatContex->oformat=outputformat;

    //2.打开视频流
    int res=avio_open(&(this->formatContex->pb),fullFileName.toStdString().c_str(),AVIO_FLAG_WRITE);
    if(res<0)
    {
        qDebug()<<"avio_open fail";
    }
    else {
       qDebug()<<"avio_open success";
    }
    //2-1新建
    AVStream*newStream=avformat_new_stream(this->formatContex,nullptr);
    if(newStream==nullptr)
    {
        qDebug()<<"avformat_new_stream fail";
    }
    else {
       qDebug()<<"avformat_new_stream success";
    }
    //2-2编码器上下文环境设置信息
    this->codecContex=newStream->codec;
    //2-3基本信息
    this->codecContex->width=this->wight;//编码视频文件宽带
    this->codecContex->height=this->hight;//高度
    this->codecContex->bit_rate=400000;//码率

    this->codecContex->framerate={24,1};//帧率
    this->codecContex->time_base={1,24};//时间基
//    time_base = this->codecContex->time_base;//设置时间基

    //2-4高级信息

    this->codecContex->gop_size=10;//I/P/B
    this->codecContex->qmax=51;//清晰度
    this->codecContex->qmin=10;
    this->codecContex->max_b_frames=0;//B压缩为0
    this->codecContex->pix_fmt=AV_PIX_FMT_YUV420P;
    this->codecContex->codec_type=AVMEDIA_TYPE_VIDEO;
    this->codecContex->codec_id=outputformat->video_codec;

    //查找编码器
    AVCodec*codec=avcodec_find_encoder(this->codecContex->codec_id);
    //3-1打开编码器
    res=avcodec_open2(this->codecContex,codec,nullptr);
    if(res!=0)
    {
        qDebug()<<"avcodec_open2 fail";
    }
    else {
        qDebug()<<"avcodec_open2 success";
    }
    //4.写文件头信息
    res=avformat_write_header(this->formatContex,nullptr);
    if(res!=0)
    {
        qDebug()<<"avformat_write_header fail";
    }
    else {
        qDebug()<<"avformat_write_header success";
    }

}

void EncodeVideo::writeTailtewr()
{
    //写尾帧
    av_write_trailer(this->formatContex);
    avio_close(this->formatContex->pb);
    avformat_free_context(this->formatContex);
    this->formatContex = nullptr;
    this->isStop = true; // 停止编码循环
}

void EncodeVideo::reciverYUV(AVFrame *yuv)
{
    YuvQueue.enqueue(yuv);
}

void EncodeVideo::reciverExit()
{
    this->st=1;
}

void EncodeVideo::reciverWightHight(int w, int h)
{
    this->wight=w;
    this->hight=h;
}



AVCodecContext *EncodeVideo::getCodecContex() const
{
    return codecContex;
}

void EncodeVideo::setCodecContex(AVCodecContext *value)
{
    codecContex = value;
}

int EncodeVideo::getHight() const
{
    return hight;
}

void EncodeVideo::setHight(int value)
{
    hight = value;
}

int EncodeVideo::getWight() const
{
    return wight;
}

void EncodeVideo::setWight(int value)
{
    wight = value;
}

QString EncodeVideo::getVideooutPath() const
{
    return videooutPath;
}

void EncodeVideo::setVideooutPath(const QString &value)
{
    videooutPath = value;
}

QString EncodeVideo::getVideooutName() const
{
    return videooutName;
}

void EncodeVideo::setVideooutName(const QString &value)
{
    videooutName = value;
}

bool EncodeVideo::getIsStop() const
{
    return isStop;
}

void EncodeVideo::setIsStop(bool value)
{
    isStop = value;
}

bool EncodeVideo::getIsClose() const
{
    return isClose;
}

void EncodeVideo::setIsClose(bool value)
{
    isClose = value;
}

bool EncodeVideo::getSt() const
{
    return st;
}

void EncodeVideo::setSt(bool value)
{
    st = value;
}

void EncodeVideo::CloseFile()
{
    this->writeTailtewr();
    qDebug()<<"writeTailer";
}

void EncodeVideo::run()
{
    while(1)
    {
        if(this->isStop==false)
        {
            if(YuvQueue.size()==0) continue;
            AVFrame*yuv=YuvQueue.dequeue();
            int res=avcodec_send_frame(this->codecContex,yuv);
            if(res!=0)
            {
                qDebug()<<"avcodec_send_frame fail";

            }
            else {
                qDebug()<<"avcodec_send_frame success";
            }


            while(res>=0)
            {

                 yuv->pts=this->pktIndex++;
                 qDebug()<<" pktIndex="<<pktIndex;
                 //将像素数据转码压缩码流数据
                 res=avcodec_receive_packet(this->codecContex,pkt);
                 if(res!=0)
                 {
                     qDebug()<<"avcodec_receive_packet fail";
                    break;
                 }
                 else {
                     qDebug()<<"avcodec_receive_packet success";
                 }
                 //写一帧数据到文件
                 res=av_interleaved_write_frame(this->formatContex,this->pkt);
                 if(res!=0)
                 {
                     qDebug()<<"av_interleaved_write_frame fail";

                 }
                 else {
                     qDebug()<<"av_interleaved_write_frame success";

                     x++;
                     if(x==300)
                     {
                         this->writeTailtewr();
                         //写入数据库
                         emit sendWriteDateBase();
                         QThread::msleep(100); // 睡眠3秒
                         //重置解码的x
                         emit sendTimeMax();

                         this->initEncode();

                     }
                 }
            }
            av_packet_unref(this->pkt);
            if(st) break;
        }
     }
}
